<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');

/**
 * Класс для генерирования таблицы по объекту модели M_Select запросу
 * 
 * @package CoreFramework
 * @version 1.0
 * @author Gennadiy Kozlenko
 */
class Table_builder {
   
   /**
    * Instance
    *
    * @access private
    * @var object
    */
   var $_obj = null;
   
   /**
    * Экземпляр модели M_Select
    *
    * @access private
    * @var object
    */
   var $_model = null;
   
   /**
    * Название таблицы
    *
    * @access private
    * @var string
    */
   var $_name = '';
   
   /**
    * Номер страницы
    *
    * @access private
    * @var integer
    */
   var $_page = 1;
   
   /**
    * Количество результатов на страницу
    *
    * @access private
    * @var integer
    */
   var $_per_page = 0;
   
   /**
    * Массив кнопок для управления списком
    *
    * @access private
    * @var array
    */
   var $_buttons = array();
   
   /**
    * Массив фильтров для фильтрации вывода
    *
    * @var array
    */
   var $_filters = array();
   
   /**
    * Массив размеров колонок
    * 
    * @var array
    */
   var $_widths = array();
   
   /**
    * Конструктор класса
    *
    * @access public
    * @return Table_Builder
    */
   function Table_builder() {
      $this->_obj =& get_instance();
      $this->_per_page = $this->_obj->config->item('per_page');
      $this->_obj->lang->load('table');
      $this->_obj->load->helper('element');
   } // end Table_Builder
   
   /**
    * Очистка результатов предыдущей работы
    *
    * @access public
    */
   function clean() {
      $this->_page = 1;
      $this->_per_page = $this->_obj->config->item('per_page');
   } // end clean
   
   /**
    * Установка названия таблицы
    *
    * @access public
    * @param string $name
    */
   function set_name($name = 'table') {
      $this->_name = $name;
   } // end set_name
   
   /**
    * Получние названия таблицы
    *
    * @access public
    * @return string
    */
   function get_name() {
      return $this->_name;
   } // end get_name
   
   /**
    * Установка объекта модели M_Select
    *
    * @access public
    * @param object $model
    */
   function set_model($model) {
      $this->_model = $model;
   } // end set_model
   
   /**
    * Получение объекта модели M_Select
    *
    * @access public
    * @return object
    */
   function get_model() {
      return $this->_model;
   } // end get_model
   
   /**
    * Установка страницы
    *
    * @access public
    * @param integer $page
    */
   function set_page($page) {
      $this->_page = $page;
   } // end set_page
   
   /**
    * Получение номера страницы
    *
    * @access public
    * @return integer
    */
   function get_page() {
      return $this->_page;
   } // end get_page
   
   /**
    * Установка количества записей на страницу
    *
    * @access public
    * @param integer $per_page
    */
   function set_per_page($per_page) {
      $this->_per_page = $per_page;
   } // end set_per_page
   
   /**
    * Получение количества записей на страницу
    *
    * @access public
    * @return integer
    */
   function get_per_page() {
      return $this->_per_page;
   } // end get_per_page
   
   /**
    * Добавление кнопки
    *
    * @access public
    * @param string $action
    * @param string $title
    * @param string $image
    */
   function add_button($action, $title, $confirmation = '', $image = '') {
      array_push($this->_buttons, array(
         'action'       => $action,
         'title'        => $title,
         'confirmation' => $confirmation,
         'image'        => !empty($image) ? array(array('image' => $image)) : array()
      ));
   } // end add_button
   
   /**
    * Убиение всех кнопок
    *
    * @access public
    */
   function clean_buttons() {
      $this->_buttons = array();
   } // end clean_buttons
   
   /**
    * Получение кнопок
    *
    * @access public
    * @return array
    */
   function get_buttons() {
      return $this->_buttons;
   } // end get_buttons
   
   /**
    * Добавление фильтра
    *
    * @access public
    * @param string $name - Название поля, к которому будет присвоен фильтр
    * @param string $title - Название фильтра
    * @param string $type - Тип фильтра. Пока поддерживаются text и select
    * @param string $compare - Функция сопоставления значения фильтра полю. Пока поддерживаются = и LIKE
    * @param array $values - Список значений для типа select
    * @param string $value - Значение по умолчанию для фильтра
    * @param boolean $use_choose - Использовать ли для select choose
    */
   function add_filter($name, $title, $type, $compare = '=', $values = array(), $value = '', $use_choose = true) {
      // Добавляем в массив choose
      if ($use_choose) {
         $values = array_merge(array('' => $this->_obj->lang->line('choose')), $values);
      }
      array_push($this->_filters, array(
         'name'    => $name,
         'title'   => $title,
         'type'    => $type,
         'compare' => $compare,
         'values'  => $values,
         'value'   => $value
      ));
   } // end add_filter
   
   /**
    * Убиение всех фильтров
    *
    * @access public
    */
   function clean_filters() {
      $this->_filters = array();
   } // end clean_filters
   
   /**
    * Получение фильтров
    *
    * @access public
    * @return array
    */
   function get_filters() {
      return $this->_filters;
   } // end get_filters
   
   /**
    * Добавление размера колонки
    * 
    * @param $name
    * @param $width
    */
   function set_width($name, $width) {
      $this->_widths[$name] = $width;
   }
   
   /**
    * Очистка размеров колонок
    * 
    */
   function clean_widths() {
      $this->_widths = array();
   }
   
   /**
    * Получение размеров колонок
    * 
    * @return array
    */
   function get_widths() {
      return $this->_widths;
   }
   
   /**
    * Получение размера колонки
    * 
    * @param $name
    * @return mixed
    */
   function get_width($name) {
      if (isset($this->_widths[$name])) {
         return $this->_widths[$name];
      }
      return false;
   }
   
   /**
    * Генерирование контента таблицы
    *
    * @access public
    * @return mixed
    */
   function generate() {
      $output = '';
      if (null === $this->_model || !is_a($this->_model, 'M_Select')) {
         return false;
      }
      if (empty($this->_name)) {
         $this->_name = strtolower(get_class($this->_model));
      }
      // Получаем из поста нужные данные
      $post = array();
      if (is_array($this->_obj->input->post($this->_name))) {
         $post = $this->_obj->input->post($this->_name);
      }
      // Обрабатываем фильтры
      // Фильтры для отображения
      $filters = array();
      // Фильтры для запроса
      $restrictions = array();
      // Фильтры из поста
      $postf = isset($post['filters']) ? $post['filters'] : array();
      foreach ($this->_filters as $filter) {
         $value = '';
         if (isset($postf[$filter['name']]) && !empty($postf[$filter['name']])) {
            $value = $postf[$filter['name']];
            // Добавляем рестрикшн
            $restriction = str_replace("_dot_", ".", $filter['name']) . ' ';
            switch (strtoupper($filter['compare'])) {
               case 'LIKE':
                  $restriction .= 'LIKE ' . $this->_obj->db->escape('%' . str_replace(array('%', '_'), array('\%', '\_'), $value) . '%');
                  break;
               default:
                  $restriction .= '= ' . $this->_obj->db->escape($value);
            }
            array_push($restrictions, $restriction);
         }
         // Формируем данные для отображения
         $element = '';
         switch ($filter['type']) {
            case 'select':
               $element = create_select($this->_name . '[filters][' . $filter['name'] . ']', $filter['values'], $value, 'class="i"');
               break;
            default:
               $element = create_text($this->_name . '[filters][' . $filter['name'] . ']', $value, 'class="i"');
         }
         array_push($filters, array(
            'title'   => $filter['title'],
            'element' => $element
         ));
      }
      // Получаем результаты
      // Применяем фильтры
      // TODO: Нужно переделать!!!
      if (0 < count($restrictions)) {
         $sql = $this->_model->get_sql();
         if (!empty($sql)) {
            foreach ($restrictions as $restriction) {
               $sql .= ' AND ' . $restriction;
            }
         }
         $this->_model->set_sql($sql);
      }

      // Сортировка
      if (isset($post['sort_field'])) {
         $field = $post['sort_field'];
         $forward = true;
         if (isset($post['forward'])) {
            $forward = (boolean) $post['forward'];
         }
         $this->_model->clean_sort();
         $this->_model->add_sort($field, $forward);
      }
      // Лимитация
      if (isset($post['page'])) {
         $this->set_page((int) $post['page']);
      }
      if (isset($post['per_page'])) {
         $this->set_per_page((int) $post['per_page']);
      }
      if (0 < $this->get_per_page()) {
         $this->_model->set_limit($this->get_per_page(), ($this->get_page() - 1) * $this->get_per_page());
      }

      $this->_model->load_results();
      // Генерируем контент таблицы
      $this->_obj->load->library('table');
      $this->_obj->table->clear();
      $this->_obj->table->set_widths($this->_widths);
      $table = '';
      $pagination = '';
      $pages = '';
      $pages_info = '';
      $this->_obj->load->helper('element');
      if (0 < $this->_model->get_count()) {
         // Результаты для вывода в таблицу
         $sort_field = $this->_model->get_sort_fields(0);
         // Добавляем строку с заголовком
         $fields = $this->_model->get_fields();
         $titles = array();
         foreach ($fields as $field) {
            if (preg_match('~_hidden$~', $field['name'])) {
               continue;
            }
            if (preg_match('~_export$~', $field['name'])) {
               continue;
            }
            $column = '';
            if ('id' == $field['name']) {
               $column = str_replace('{%table%}', $this->_name, $this->_obj->lang->line('table_all_checkbox'));
            } else {
               $title = $field['name'];
               $model_name = preg_replace('~^m_select_~', '', strtolower(get_class($this->_model)));
               if (isset($field['title']) && !empty($field['title'])) {
                  $title = $field['title'];
               } elseif (false !== $this->_obj->lang->line($model_name . '_' . $field['name'] . '_header')) {
                  $title = $this->_obj->lang->line($model_name . '_' . $field['name'] . '_header');
               }
               $forward = true;
               if (isset($field['sort']) && $field['sort'] && $field['name'] == $sort_field) {
                  $title = str_replace('{%title%}', $title, $this->_obj->lang->line('table_active_title'));
                  $forward = !$this->_model->get_sort_directions(0);
               } else {
                  $title = str_replace('{%title%}', $title, $this->_obj->lang->line('table_title'));
               }
               $column = $title;
               if (isset($field['sort']) && $field['sort']) {
                  $column = str_replace(array('{%table%}', '{%field%}', '{%forward%}', '{%title%}'), 
                                        array($this->_name, $field['name'], (string) $forward, $title), 
                                        $this->_obj->lang->line('table_column_title'));
               }
            }
            $titles[$field['name']] = $column;
            //array_push($titles, $column);
         }
         $results = $this->_model->get_results();
         // Обрабатываем результаты
         foreach ($results as $id => $result) {
            foreach (array_keys($result) as $key) {
               if (preg_match('~_hidden$~', $key)) {
                  unset($result[$key]);
               }
               if (preg_match('~_export$~', $key)) {
                  unset($result[$key]);
               }
            }
            $results[$id] = $result;
            if (isset($result['id'])) {
               $result['id'] = str_replace(array('{%table%}', '{%id%}'), array($this->_name, $result['id']), $this->_obj->lang->line('table_checkbox'));
            }
            $results[$id] = $result;
         }
         array_unshift($results, $titles);
         $table = $this->_obj->table->generate($results);
         // Постраничный вывод
         $start = ($this->_page - 1) * $this->_per_page;
         $count = $this->_model->get_count();
         $end = $start + $count - 1;
         $all_count = $this->_model->get_all_count();
         $pagination = '';
         if ($count < $all_count) {
            $this->_obj->load->library('pagination');
            $this->_obj->pagination->set_template(
               array(
                  'open'      => $this->_obj->lang->line('page_open'),
                  'close'     => $this->_obj->lang->line('page_close'),
                  'page_open' => $this->_obj->lang->line('page_page_open'),
                  'page_close'=> $this->_obj->lang->line('page_page_close'),
                  'prev_link' => str_replace('{%table%}', $this->_name, $this->_obj->lang->line('page_prev_link')),
                  'prev'      => str_replace('{%table%}', $this->_name, $this->_obj->lang->line('page_prev')),
                  'next_link' => str_replace('{%table%}', $this->_name, $this->_obj->lang->line('page_next_link')),
                  'next'      => str_replace('{%table%}', $this->_name, $this->_obj->lang->line('page_next')),
                  'page_link' => str_replace('{%table%}', $this->_name, $this->_obj->lang->line('page_page_link')),
                  'page'      => $this->_obj->lang->line('page_page'),
                  'nav_sep'   => $this->_obj->lang->line('page_nav_sep'),
                  'page_sep'  => $this->_obj->lang->line('page_page_sep'),
                  'caption'   => $this->_obj->lang->line('page_caption')
               )
            );
            $this->_obj->pagination->set_page($this->_page);
            $this->_obj->pagination->set_num_pages(ceil($all_count / $this->_per_page));
            $pagination = $this->_obj->pagination->create_links();
         }
         $pages = create_select('', $this->_obj->config->item('per_page_nums'), $this->_per_page, 'onchange="return set_per_page(\'' . $this->_name . '\', this.value)"');
         $pages_info = str_replace(array('{%start%}', '{%end%}', '{%all%}'), array($start + 1, $end + 1, $all_count), $this->_obj->lang->line('table_pages_info'));
      } else {
         $table = $this->_obj->parser->parse('common/table/no_results.html', array(), true);
      }
      // Оборачиваем это дело в шаблон
      $data = array(
         'content'      => $table,
         'pages'        => $pages,
         'per_page'     => (string) $this->_per_page,
         'page'         => (string) $this->_page,
         'pages_info'   => $pages_info,
         'pagination'   => $pagination,
         'sort_field'   => $this->_model->get_sort_fields(0),
         'forward'      => (string) $this->_model->get_sort_directions(0),
         'buttons'      => $this->_buttons,
         'filters'      => $filters,
         'show_filters' => empty($filters) ? array() : array(array()),
         'name'         => $this->_name,
      );
      $content = $this->_obj->parser->parse('common/table/results.html', $data, true);
      
      // Основной шаблон страницы
      $data = array(
         'content' => $content
      );
      $output = $this->_obj->parser->parse('common/table/table.html', $data, true);
      return $output;
   } // end generate
   
}
